package com.apache.client.common;

import com.apache.api.api.IAuthentication;
import com.apache.api.vo.AouthSecurity;
import com.apache.api.vo.ResultMsg;
import com.apache.api.vo.Token;
import com.apache.database.constant.SpringContextLoader;
import com.apache.exception.BusinessException;
import com.apache.license.validator.LicenseValidate;
import com.apache.oscache.OsCacheManager;
import com.apache.passport.common.PassportHelper;
import com.apache.tools.StrUtil;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * @description:
 * @author: Hou Dayu
 * @date: Created in 2021/2/1
 */
public class TokenInterceptor extends HandlerInterceptorAdapter {

    private Logger logger = LoggerFactory.getLogger("interceptor");
    private String sysCode;

    public TokenInterceptor(String sysCode) {
        this.sysCode = sysCode;
    }
    /**
     * 方法执行前拦截
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {
        //request.getSession().setAttribute("ctx", request.getContextPath());
        if (handler instanceof HandlerMethod) {//方法级拦截
            boolean mark = doCheckInfo(request, response);//验证请求是否有效
            if (!mark) {
                response.setStatus(500);
                return false;
            }
            Method method = ((HandlerMethod) handler).getMethod();
            //安全验证
            AouthSecurity aouthSecurity = method.getAnnotation(AouthSecurity.class);
            if (aouthSecurity != null) {//安全验证
                String path = request.getServletPath();
                String tokenCookie = PassportHelper.getInstance().getTokenId(request);
                String messageError ="当前请求地址需要登录后访问,请你登录后操作!";
                //需要验证用户登录
                if(aouthSecurity.token() || aouthSecurity.security()) {
                    if(StrUtil.isNull(tokenCookie)){
                        logger.warn("当前请求地址("+path+")需要登录后访问,当前用户未登录!");
                        toErrorPage(request,response,messageError);
                        return false;
                    }
                }
                //需要验证请求权限
                if(aouthSecurity.security()){
                    boolean aouthMark = false;
                    Object user = OsCacheManager.getInstance().getLoginUser(tokenCookie);
                    if(StrUtil.isNotNull(aouthSecurity.user()) && !StrUtil.isEmpty(user)) {
                        JSONObject obj = JSONObject.fromObject(user);
                        String userEname = obj.getString("userEname");
                        List<String> list = Arrays.asList(aouthSecurity.user().split(","));
                        if(!list.contains(userEname)){
                            response.setStatus(403);
                            toErrorPage(request,response,"您没有当前请求地址访问权限,授权后再进行操作!");
                            return false;
                        }
                    }
                    //获取访问权限验证自定义扩展(beanId:myAuthentication)
                    IAuthentication iAouth = (IAuthentication) SpringContextLoader.getBean("myAuthentication");
                    if(iAouth == null){
                        iAouth = new DefaultIAuthentication();
                    }
                    if (!aouthMark) {
                        request.setAttribute("sys-ename-code",sysCode);
                        aouthMark = iAouth.aouthSecurity(user, request, response,aouthSecurity.role(),aouthSecurity.userType());
                    }
                    if (!aouthMark) {
                        logger.warn("当前请求地址(" + path + ")访问权限验证不能过!");
                        messageError ="您没有当前请求地址访问权限,授权后再进行操作!";
                        toErrorPage(request,response,messageError);
                        return false;
                    }
                }
            }
            //防止重复提交
            Token annotation = method.getAnnotation(Token.class);
            if (annotation != null) {
                boolean needSaveSession = annotation.save();
                if (needSaveSession) {//防止重复提交
                    HttpSession session = request.getSession(true);
                    String uuid = UUID.randomUUID().toString();
                    if (null != session)
                        session.setAttribute("formToken", uuid);
                }
                boolean needRemoveSession = annotation.remove();
                if (needRemoveSession) {//移出token
                    if (isRepeatSubmit(request)) {
                        response.setStatus(302);
                        return false;
                    }
                    request.getSession(false).removeAttribute("formToken");
                }
            }
            return true;
        } else {
            return super.preHandle(request, response, handler);
        }
    }

    /**
     * 跳转到错误页面
     */
    private void toErrorPage(HttpServletRequest request,HttpServletResponse response,String errorMessage) throws ServletException, IOException {
        String header = request.getHeader("X-Requested-With");
        boolean isAjax = "XMLHttpRequest".equals(header) ? true : false;
        if (isAjax) {//ajax请求
            response.setContentType("text/html;charset=utf-8");
            try {
                PrintWriter writer = response.getWriter();
                writer.write(errorMessage);
                writer.flush();
                writer.close();
            } catch (IOException e) {
            }
        }
        // response.setHeader("messageError", errorMessage);
        String gotoUrl = request.getContextPath()+"/errorPage?Errorcode=invalid-00000003";
        response.sendRedirect(gotoUrl);//服务器IP或mac地址未授权
    }
    /**
     * 判断是否重复提交
     */
    private boolean isRepeatSubmit(HttpServletRequest request) {
        String serverToken = StrUtil.doNull(String.valueOf(request.getSession(false).getAttribute("formToken")), "");
        String clinetToken = request.getParameter("formToken");
        if (StrUtil.isNotNull(clinetToken)) {
            if (StrUtil.isNull(serverToken) || !serverToken.equals(clinetToken)) {
                return true;
            }
            request.setAttribute("formToken", serverToken);
        }
        return false;
    }

    /**
     * license验证
     */
    private boolean doCheckInfo(HttpServletRequest request, HttpServletResponse response)
            throws BusinessException {
        String path = request.getRequestURI();
        try {
            long lastTime = LicenseValidate.getInstance().isTimeByDay(7);//返回要提醒的天数
            if (lastTime == -1) {
                response.sendRedirect(request.getContextPath() + "/errorPage?Errorcode=invalid-00000001");//License 超过有效期！
                return false;
            } else {
                if (lastTime <= 7) {//有效期验证
                    /////////////////license将到期提醒操作////////////////////
                    warnLicenseInfo(request, response, lastTime);
                }
            }

            if (LicenseValidate.getInstance().isFormal()) {//正式license号
                if (path.indexOf("errorPage") != -1) {
                    return true;
                }
                if (!LicenseValidate.getInstance().isEffective()) {
                    String header = request.getHeader("X-Requested-With");
                    boolean isAjax = "XMLHttpRequest".equals(header) ? true : false;
                    if (isAjax) {
                        JSONObject array = JSONObject.fromObject(new ResultMsg("F", "产品授权已过期"));
                        response.setContentType("text/html;charset=utf-8");
                        PrintWriter writer = response.getWriter();
                        writer.write(array.toString());
                        writer.flush();
                        writer.close();
                    } else {
                        response.sendRedirect(request.getContextPath()
                                + "/errorPage?Errorcode=invalid-00000002");//服务器IP或mac地址未授权
                    }
                    return false;
                }
            }
        } catch (Exception e) {
            try {//服务器IP或mac地址未授权
                if (path.indexOf("error") != -1 || path.indexOf("invalid.jsp") != -1) {
                    return true;
                }
                response.sendRedirect(request.getContextPath() + "/errorPage");
            } catch (IOException e1) {
            }
            return false;
        }
        return true;
    }

    /**
     * 提示用户license即将到期
     */
    protected void warnLicenseInfo(HttpServletRequest request, HttpServletResponse response,
                                   long lastTime) {
        request.getSession().setAttribute("licenseTodata", lastTime);
    }
}
